use core::ffi::c_void;

use crate::{
    protocol::console::{input::EfiSimpleTextInputProtocol, output::EfiSimpleTextOutputProtocol},
    services::{boot::EfiBootServices, runtime::EfiRuntimeServices},
    Char16, EfiGuid, EfiHandle,
};

#[repr(C)]
pub struct EfiTableHeader {
    /// 64-bit 的签字用来表明表的类型
    pub signature: u64,
    /// 高 16 位包含主版本号，低 16 位为次版本号。
    /// 次版本号（二进制编码的十进制数，非 BCD 码）的范围：00..99
    pub revision: u32,
    /// 包含 header 在内的整个表的大小。
    pub header_size: u32,
    /// 整个表的 32-bit CRC，计算时，该字段初始为 0，一共计算 header_size 个字节，也就说包括 header 在内。
    pub crc32: u32,
    _reversed: u32,
}

#[repr(C)]
pub struct EfiSystemTable {
    /// header 包含表的签字和表的版本，以及表结构的大小和一个 32-bit 的 CRC 用于验证表的内容是否有效。
    pub hdr: EfiTableHeader,
    /// null 结尾的字符串指针，用来标识为平台提供系统固件的厂商。
    pub firmware_vendor: *mut Char16,
    /// 固件厂商指定的版本信息
    pub firmware_revision: u32,
    /// 活动的控制台输入设备。该 handle 必须支持
    /// [`EfiSimpleTextInputProtocol`](crate::::protocol::console::input::EfiSimpleTextInputProtocol) 协议和
    /// [`EfiSimpleTextInputExProtocol`](crate::::protocol::console::input::EfiSimpleTextInputExProtocol) 协议。
    ///
    /// 即便没有活动的控制台，这些协议也必须存在。
    pub console_in_handle: EfiHandle,
    /// 和 console_in_handle 相关联的 `EfiSimpleTextInputProtocol` 协议接口的指针。
    pub con_in: *mut EfiSimpleTextInputProtocol,
    pub console_out_handle: EfiHandle,
    pub con_out: *mut EfiSimpleTextOutputProtocol,
    pub standard_error_handle: EfiHandle,
    pub std_err: *mut EfiSimpleTextOutputProtocol,
    pub runtime_services: *mut EfiRuntimeServices,
    pub boot_services: *mut EfiBootServices,
    pub number_of_table_entries: usize,
    pub configuration_table: *mut EfiConfigurationTable,
}
impl EfiSystemTable {
    pub const EFI_SYSTEM_TABLE_SIGNATURE: u64 = 0x5453595320494249;
    pub const EFI_2_90_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (90));
    pub const EFI_2_80_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (80));
    pub const EFI_2_70_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (70));
    pub const EFI_2_60_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (60));
    pub const EFI_2_50_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (50));
    pub const EFI_2_40_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (40));
    pub const EFI_2_31_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (31));
    pub const EFI_2_30_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (30));
    pub const EFI_2_20_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (20));
    pub const EFI_2_10_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (10));
    pub const EFI_2_00_SYSTEM_TABLE_REVISION: u32 = ((2 << 16) | (00));
    pub const EFI_1_10_SYSTEM_TABLE_REVISION: u32 = ((1 << 16) | (10));
    pub const EFI_1_02_SYSTEM_TABLE_REVISION: u32 = ((1 << 16) | (02));
    pub const EFI_SPECIFICATION_VERSION: u32 = Self::EFI_SYSTEM_TABLE_REVISION;
    pub const EFI_SYSTEM_TABLE_REVISION: u32 = Self::EFI_2_90_SYSTEM_TABLE_REVISION;
}

pub struct EfiConfigurationTable {
    pub vendor_guid: EfiGuid,
    pub vendor_table: *mut c_void,
}
